#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <errno.h>
#include <time.h>
#include <libgen.h>
#include <fcntl.h>

#define MAX_EPOLL_EVENTS 1024
#define MAX_BUFFER_SIZE 4096

typedef int NCALLBACK(int, int, void *);

struct ntyevent
{
    int fd;
    int events;

    void *arg; // 事件回调函数的参数3, 实际传入的是一个struct ntyreactor结构体指针
    int (*callback)(int fd, int events, void *arg);

    int status; // 当前事件是否位于epoll集合中: 1表示在, 0表示不在
    char buffer[MAX_BUFFER_SIZE];
    int length;

    long last_active; // 最后一次活跃的时间
};

// Reactor主体
struct ntyreactor
{
    int epoll_fd;
    struct ntyevent *events;
};

// 创建一个Tcp Server
int init_server(char* ip, short port);
// 向reactor中添加一个服务器监听事件
int ntyreactor_addlistener(struct ntyreactor *reactor, int fd, NCALLBACK callback);

// 初始化reactor
struct ntyreactor* ntyreactor_init();
// 销毁reactor
int ntyreactor_destroy(struct ntyreactor* reactor);
// reactor 运行函数
int ntyreactor_run(struct ntyreactor* reactor);

//将一个fd封装到事件结构中
int nty_event_set(struct ntyevent* ev, int fd, int event, int length, int status, NCALLBACK callback, void* arg);
//将一个事件添加/更新到epoll事件表中
int nty_event_add(int epoll_fd, struct ntyevent* ev);
//将一个事件移出epoll事件表
int nty_event_del(int epoll_fd, struct ntyevent* event);

/*三个可选择的回调函数*/
int accept_callback(int fd, int events, void* arg);
int recv_callback(int fd, int events, void* arg);
int send_callback(int fd, int events, void* arg);

int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        printf("usage: ./%s [ip] [port]\n", basename(argv[0]));
        exit(EXIT_FAILURE);
    }

    char *ip = argv[1];
    short port = atoi(argv[2]);
    int sock_fd;

    sock_fd = init_server(ip, port);
    /*初始化一个Tcp Server*/
    struct ntyreactor* reactor = ntyreactor_init();
    if(reactor == NULL)
    {
        printf("Error in %s(), ntyreactor_init: create reactor error\n", __func__);
        exit(EXIT_FAILURE);
    }

    // 将Tcp Server添加到reactor事件集中
    ntyreactor_addlistener(reactor, sock_fd, accept_callback);
    // 运行reactor
    ntyreactor_run(reactor);
    // 销毁
    ntyreactor_destroy(reactor);
    close(sock_fd);
    return 0;
}

int init_server(char* ip, short port)
{
    int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(sock_fd == -1)
    {
        printf("Error in %s(), socket: %s\n", __func__, strerror(errno));
        return -1;
    }
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &server_addr.sin_addr);
    if(inet_pton(AF_INET, ip, (void*)&server_addr.sin_addr.s_addr) == -1)
    {
        printf("Error is %s(), inet_pton: %s\n", __func__, strerror(errno));
        return -1;
    }
    server_addr.sin_port = htons(port);

    if(bind(sock_fd, (const struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
    {
        printf("Error in %s(), bind: %s\n", __func__, strerror(errno));
        return -1;
    }

    if(listen(sock_fd, 20) == -1)
    {
        printf("Error in %s(), listen: %s\n", __func__, strerror(errno));
        return -1;
    }

    printf("Listen start [%s:%d]...\n", inet_ntoa(server_addr.sin_addr)); /*转换为点分十进制格式的字符串。这个字符串随后可以被printf等函数使用。*/
    return sock_fd;
}

struct ntyreactor *ntyreactor_init()
{
    struct ntyreactor *reactor = (struct ntyreactor*)malloc(sizeof(struct ntyreactor));
    if(reactor == NULL)
        return NULL;
    memset(reactor, 0, sizeof(struct ntyreactor));

    reactor->epoll_fd = epoll_create(1);
    if(reactor->epoll_fd == -1)
    {
        printf("Error in %s(), epoll_create:%s\n", __func__, strerror(errno));
        free(reactor);
        return NULL;
    }

    reactor->events = (struct ntyevent*)malloc(sizeof(struct ntyevent) * MAX_EPOLL_EVENTS);
    if(reactor->events == NULL)
    {
        printf("Error in %s(), malloc: %s\n", __func__, strerror(errno));
        close(reactor->epoll_fd);
        free(reactor);
        return NULL;
    }
}

int ntyreactor_destroy(struct ntyreactor* reactor)
{
    if(reactor == NULL)
    {
        printf("Error is %s(): %s\n", __func__, "reactor arg is NULL");
        return -1;
    }

    //关闭epoll_fd、销毁事件集，释放结构
    close(reactor->epoll_fd);
    free(reactor->events);

    free(reactor);
    return 0;
}

int ntyreactor_run(struct ntyreactor* reactor)
{
    if(reactor == NULL || reactor->epoll_fd < 0 || reactor->events == NULL)
    {
        printf("Error in %s(): %s\n", __func__, "reactor arg is error");
        return -1;
    }

    struct epoll_event ep_events[MAX_EPOLL_EVENTS + 1];

    int nready;
    while(1)
    {
        nready = epoll_wait(reactor->epoll_fd, ep_events, MAX_EPOLL_EVENTS, 1000);

        if(nready == -1)
        {
            // 非阻塞读取或者写入数据发生的错误
            if(errno == EAGAIN || errno == EWOULDBLOCK)
                continue;
            printf("Error in %s(), epoll_wait: %s\n", __func__, strerror(errno));
            return -1;
        }
        else if(nready == 0)
            continue;
        else
        {
            int i;
            for(i == 0; i < nready; i++)
            {
                struct ntyevent* ev = (struct ntyevent*)ep_events[i].data.ptr;
                //如果事件可读 并且是 我们感兴趣的事件
                if((ep_events[i].events & EPOLLIN) && (ev->events & EPOLLIN))
                    ev->callback(ev->fd, ev->events, ev->arg);
                //如果事件可写
                if((ep_events[i].events & EPOLLOUT) && (ev->events & EPOLLOUT))
                    ev->callback(ev->fd, ev->events, ev->arg);
            }
        }
    }
    return 0;
}

int ntyreactor_addlistener(struct ntyreactor *reactor, int fd, NCALLBACK callback)
{
    if(reactor == NULL || fd < 0 || callback == NULL)
    {
        printf("Error in %s(): %s\n", __func__, "arg error");
        return -1;
    }
    nty_event_set(&reactor->events[fd], fd, EPOLLIN, 0, 0, callback, reactor);
    nty_event_add(reactor->epoll_fd, &reactor->events[fd]);

    return 0;
}

int nty_event_set(struct ntyevent* ev, int fd, int event, int length, int status, NCALLBACK callback, void* arg)
{
    if(ev == NULL || fd < 0 || event < 0 || length < 0 || callback == NULL || arg == NULL || status < 0)
    {
        printf("Error in %s(): %s\n", __func__, "arg error");
        return -1;
    }

    ev->fd = fd;
    ev->events = event;
    ev->arg = arg;
    ev->callback = callback;
    ev->status = status;
    ev->length = length;
    ev->last_active = time(NULL);

    return 0;
}

int nty_event_add(int epoll_fd, struct ntyevent* ev)
{
    if(epoll_fd < 0 || ev == NULL)
    {
        printf("Error in %s(): %s\n", __func__, "arg error");
        return -1;
    }

    struct epoll_event ep_event;
    memset(&ep_event, 0, sizeof(ep_event));
    ep_event.events = ev->events;
    ep_event.data.ptr = ev;

    int op;
    if(ev->status == 0)
    {
        op = EPOLL_CTL_ADD;
        ev->status = 1;
    }
    else
        op = EPOLL_CTL_MOD;

    if(epoll_ctl(epoll_fd, op, ev->fd, &ep_event) == -1)
    {
        printf("Error in %s(): %s\n", __func__, strerror(errno));
        return -1;
    }
    return 0;
}

int nty_event_del(int epoll_fd, struct ntyevent* ev)
{
    if(epoll_fd < 0 || ev == NULL || ev->status != 1)
    {
        printf("Error in %s(): %s\n", __func__, "ev arg is error");
        return -1;
    }

    struct epoll_event ep_event;
    memset(&ep_event, 0, sizeof(ep_event));
    ep_event.data.ptr = ev;

    ev->status = 0;

    if(epoll_ctl(epoll_fd, EPOLL_CTL_DEL, ev->fd, &ep_event) == -1)
    {
        printf("Error in %s(), epoll_ctl: %s\n", __func__, strerror(errno));
        return -1;
    }

    return 0;
}

int accept_callback(int fd, int events, void* arg)
{
    struct ntyreactor* reactor = (struct ntyreactor*)arg;
    struct ntyevent* ev = reactor->events + fd;

    struct sockaddr_in cli_addr;
    memset(&cli_addr, 0, sizeof(cli_addr));

    socklen_t len = sizeof(cli_addr);

    int cli_fd;
    cli_fd = accept(ev->fd, (struct sockaddr*)&cli_addr, &len);
    if(cli_fd == -1)
    {
        printf("Error in %s(), accept: %s\n", __func__, strerror(errno));
        return -1;
    }
    int i;
    do
    {
        for(int i = 5; i < MAX_EPOLL_EVENTS; i++)
        {
            if(reactor->events[i].status == 0)
                break;
        }

        if(i == MAX_EPOLL_EVENTS)
        {
            printf("Error in %s(): max connect limit[%d]\n", __func__, MAX_EPOLL_EVENTS);
            return -1;
        }

        int flag = 0;
        if((flag = fcntl(cli_fd, F_SETFL, O_NONBLOCK)) < 0)
        {
            printf("Error in %s(), fcntl: %s\n", __func__, strerror(errno));
            return -1;
        }
    } while (0); 
}

int recv_callback(int fd, int events, void* arg)
{
    struct ntyreactor* reactor = (struct ntyreactor*)arg;
    struct ntyevent* ev = reactor->events + fd;
    nty_event_del(reactor->epoll_fd, ev);
    int rc = recv(ev->fd, ev->buffer, MAX_BUFFER_SIZE, 0);
    if(rc < 0)
    {
        printf("Error in %s(): recv: %s\n", __func__, strerror(errno));
        close(ev->fd);
    }
    else if(rc == 0)
    {
        printf("Client closed the connection, fd = %d\n", ev->fd);
        close(ev->fd);
    }
    else
    {
        ev->buffer[rc] = '\0';
        printf("Recv[fd = %d] : %s\n", ev->fd, ev->buffer);
        nty_event_set(ev, ev->fd, EPOLLOUT, rc, 0, send_callback, reactor);
        nty_event_add(reactor->epoll_fd, ev);
    }
    return rc;
}

int send_callback(int fd, int events, void* arg)
{
    struct ntyreactor* reactor = (struct ntyreactor*)arg;
    struct ntyevent* ev = reactor->events + fd;
    int rc = send(ev->fd, ev->buffer, ev->length, 0);
    if(rc > 0)
    {
        printf("Send[fd = %d]: %s\n", ev->fd, ev->buffer);
        nty_event_del(reactor->epoll_fd, ev);
        nty_event_set(ev, ev->fd, EPOLLIN, 0, 0, recv_callback, reactor);
        nty_event_add(reactor->epoll_fd, ev);
    }
    else //send失败
    {
        printf("Error in %s(), send: %s\n", __func__, strerror(errno));
 
        // 关闭、移除
        close(ev->fd);
        nty_event_del(reactor->epoll_fd, ev);
    }
 
    return rc;
}

